package com.zone.infrastructure.persistent.repository;

import cn.hutool.core.bean.BeanUtil;
import com.google.common.collect.Lists;
import com.zone.domain.acticity.model.aggregate.CreateActivityOrderAggregate;
import com.zone.domain.acticity.model.aggregate.PartakeActivityOrderAggregate;
import com.zone.domain.acticity.model.entity.*;
import com.zone.domain.acticity.model.valobj.ActivityOrderStateEnum;
import com.zone.domain.acticity.model.valobj.ActivitySkuStockSubTaskVO;
import com.zone.domain.acticity.repository.IActivityRepository;
import com.zone.infrastructure.event.MessageProduct;
import com.zone.infrastructure.persistent.dao.*;
import com.zone.infrastructure.persistent.po.*;
import com.zone.infrastructure.persistent.redis.IRedisService;
import com.zone.types.common.Constants;
import com.zone.types.exception.BizException;
import com.zone.types.utils.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: zongzi
 * @description: 活动相关
 * @date: 2024/6/30
 */
@Service
@Repository
public class ActivityRepository implements IActivityRepository {
    @Autowired
    private IRaffleActivitySkuDao raffleActivitySkuDao;
    @Autowired
    private IRaffleActivityDao raffleActivityDao;
    @Autowired
    private IRaffleActivityCountDao raffleActivityCountDao;
    @Autowired
    private IRaffleActivityOrderDao raffleActivityOrderDao;
    @Autowired
    private IRaffleActivityAccountDao raffleActivityAccountDao;
    @Autowired
    private IRaffleActivityAccountMonthDao raffleActivityAccountMonthDao;
    @Autowired
    private IRaffleActivityAccountDayDao raffleActivityAccountDayDao;
    @Autowired
    private IUserRaffleOrderDao userRaffleOrderDao;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private IRedisService redisService;
    @Autowired
    private MessageProduct activitySkuZeroProduct;
    /** 消息主题 */
    @Value("${spring.rabbitmq.topic.activity_sku_zero}")
    private String topic;

    private static final DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
    private static final DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");


    public ActivitySkuEntity queryActivitySku(Long sku) {
        RaffleActivitySku raffleActivitySku = raffleActivitySkuDao.get(sku);
        return BeanUtil.copyProperties(raffleActivitySku, ActivitySkuEntity.class);
    }

    @Override
    public ActivityEntity queryActivity(Long activityId) {
        RaffleActivity raffleActivity = raffleActivityDao.get(activityId);
        return BeanUtil.copyProperties(raffleActivity, ActivityEntity.class);
    }

    @Override
    public ActivityCountEntity queryActivityCount(Long activityCountId) {
        RaffleActivityCount raffleActivityCount = raffleActivityCountDao.get(activityCountId);
        return BeanUtil.copyProperties(raffleActivityCount, ActivityCountEntity.class);
    }

    @Override
    public ActivityOrderEntity createNoPayActivityOrder(CreateActivityOrderAggregate createActivityOrderAggregate) {
        String userId = createActivityOrderAggregate.getUserId();
        ActivityEntity activityEntity = createActivityOrderAggregate.getActivityEntity();
        Long activityId = activityEntity.getActivityId();
        ActivityCountEntity activityCountEntity = createActivityOrderAggregate.getActivityCountEntity();
        // 活动次数流水单
        RaffleActivityOrder raffleActivityOrder = new RaffleActivityOrder();
        raffleActivityOrder.setUserId(userId);
        raffleActivityOrder.setSku(createActivityOrderAggregate.getSku());
        raffleActivityOrder.setActivityId(activityId);
        raffleActivityOrder.setActivityName(activityEntity.getActivityName());
        raffleActivityOrder.setStrategyId(activityEntity.getStrategyId());
        raffleActivityOrder.setOrderId(RandomStringUtils.randomNumeric(12));
        raffleActivityOrder.setOrderTime(new Date());
        raffleActivityOrder.setTotalCount(activityCountEntity.getTotalCount());
        raffleActivityOrder.setDayCount(activityCountEntity.getDayCount());
        raffleActivityOrder.setMonthCount(activityCountEntity.getMonthCount());
        raffleActivityOrder.setState(ActivityOrderStateEnum.CREATE.getCode());
        raffleActivityOrder.setOutBusinessNo(createActivityOrderAggregate.getOutBusinessNo());
        // 用户活动次数账号-总
        RaffleActivityAccount raffleActivityAccount = new RaffleActivityAccount();
        raffleActivityAccount.setUserId(userId);
        raffleActivityAccount.setActivityId(activityId);
        raffleActivityAccount.setTotalCount(activityCountEntity.getTotalCount());
        raffleActivityAccount.setTotalCountSurplus(activityCountEntity.getTotalCount());
        raffleActivityAccount.setDayCount(activityCountEntity.getDayCount());
        raffleActivityAccount.setDayCountSurplus(activityCountEntity.getDayCount());
        raffleActivityAccount.setMonthCount(activityCountEntity.getMonthCount());
        raffleActivityAccount.setMonthCountSurplus(activityCountEntity.getMonthCount());
        // 用户活动次数账号-月
        RaffleActivityAccountMonth raffleActivityAccountMonth = new RaffleActivityAccountMonth();
        raffleActivityAccountMonth.setUserId(userId);
        raffleActivityAccountMonth.setActivityId(activityId);
        raffleActivityAccountMonth.setMonth(RaffleActivityAccountMonth.currentMonth());
        raffleActivityAccountMonth.setMonthCount(activityCountEntity.getMonthCount());
        raffleActivityAccountMonth.setMonthCountSurplus(activityCountEntity.getMonthCount());
        // 用户活动次数账号-日
        RaffleActivityAccountDay raffleActivityAccountDay = new RaffleActivityAccountDay();
        raffleActivityAccountDay.setUserId(userId);
        raffleActivityAccountDay.setActivityId(activityId);
        raffleActivityAccountDay.setDay(RaffleActivityAccountDay.currentDay());
        raffleActivityAccountDay.setDayCount(activityCountEntity.getDayCount());
        raffleActivityAccountDay.setDayCountSurplus(activityCountEntity.getDayCount());
        // 编程式事务
        String lockKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_ACCOUNT_LOCK, userId, activityId);
        RLock lock = redisService.getLock(lockKey);
        try {
            lock.lock();
            transactionTemplate.execute(status -> {
                try {
                    // 保存流水单
                    raffleActivityOrderDao.insert(raffleActivityOrder);
                    // 更新 or 新增活动账户
                    int count = raffleActivityAccountDao.update(raffleActivityAccount);
                    if (count == 0) {
                        raffleActivityAccountDao.insert(raffleActivityAccount);
                    }
                    // 查询更新/新增后的总账户
                    RaffleActivityAccount afterAccount = raffleActivityAccountDao.get(userId, activityId);
                    // 更新 or 新增活动账户-月
                    RaffleActivityAccountMonth existedAccountMonth = raffleActivityAccountMonthDao.get(userId, activityId, RaffleActivityAccountMonth.currentMonth());
                    if (Objects.isNull(existedAccountMonth)) {
                        raffleActivityAccountMonth.setMonthCount(afterAccount.getMonthCount());
                        raffleActivityAccountMonth.setMonthCountSurplus(afterAccount.getMonthCountSurplus());
                        raffleActivityAccountMonthDao.insert(raffleActivityAccountMonth);
                    } else {
                        raffleActivityAccountMonthDao.update(raffleActivityAccountMonth);
                    }
                    // 更新 or 新增活动账户-日
                    RaffleActivityAccountDay existedAccountDay = raffleActivityAccountDayDao.get(userId, activityId, RaffleActivityAccountDay.currentDay());
                    if (Objects.isNull(existedAccountDay)) {
                        raffleActivityAccountDay.setDayCount(afterAccount.getDayCount());
                        raffleActivityAccountDay.setDayCountSurplus(afterAccount.getDayCountSurplus());
                        raffleActivityAccountDayDao.insert(raffleActivityAccountDay);
                    } else {
                        raffleActivityAccountDayDao.update(raffleActivityAccountDay);
                    }
                    return 1;
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;

                }
            });
        } finally {
            lock.unlock();
        }
        return RaffleActivityOrder.convert2Entity(raffleActivityOrder);
    }

    @Override
    public ActivityOrderEntity createPayActivityOrder(CreateActivityOrderAggregate createActivityOrderAggregate) {
        String userId = createActivityOrderAggregate.getUserId();
        ActivityEntity activityEntity = createActivityOrderAggregate.getActivityEntity();
        Long activityId = activityEntity.getActivityId();
        ActivityCountEntity activityCountEntity = createActivityOrderAggregate.getActivityCountEntity();
        ActivitySkuEntity activitySku = createActivityOrderAggregate.getActivitySku();
        // 活动次数流水单
        RaffleActivityOrder raffleActivityOrder = new RaffleActivityOrder();
        raffleActivityOrder.setUserId(userId);
        raffleActivityOrder.setSku(createActivityOrderAggregate.getSku());
        raffleActivityOrder.setActivityId(activityId);
        raffleActivityOrder.setActivityName(activityEntity.getActivityName());
        raffleActivityOrder.setStrategyId(activityEntity.getStrategyId());
        raffleActivityOrder.setOrderId(RandomStringUtils.randomNumeric(12));
        raffleActivityOrder.setOrderTime(new Date());
        raffleActivityOrder.setTotalCount(activityCountEntity.getTotalCount());
        raffleActivityOrder.setDayCount(activityCountEntity.getDayCount());
        raffleActivityOrder.setMonthCount(activityCountEntity.getMonthCount());
        raffleActivityOrder.setProductAmount(activitySku.getProductAmount());
        raffleActivityOrder.setState(ActivityOrderStateEnum.WAIT_PAY.getCode());
        raffleActivityOrder.setOutBusinessNo(createActivityOrderAggregate.getOutBusinessNo());

        // 保存流水单
        raffleActivityOrderDao.insert(raffleActivityOrder);
        return RaffleActivityOrder.convert2Entity(raffleActivityOrder);
    }

    @Override
    public void assembleSkuStock(Long sku, Integer stockCount) {
        String activityStockCacheKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_STOCK_KEY, sku);
        redisService.setAtomicLong(activityStockCacheKey, stockCount);
    }

    @Override
    public boolean descActivitySkuStock(Long sku) {
        String activityStockCacheKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_STOCK_KEY, sku);
        long activitySkuStockCount = redisService.decr(activityStockCacheKey);
        if (activitySkuStockCount < 0) {
            // 更新为0
            redisService.setAtomicLong(activityStockCacheKey, 0);
            return false;
        }
        // 滑块锁
        String countKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_STOCK_COUNT_KEY, sku, activitySkuStockCount);
        redisService.setNx(countKey, "lock");
        if (activitySkuStockCount == 0) {
            // 库存扣减到0，发送mq，清空sku库存数量为0
            activitySkuZeroProduct.sendMessage(topic, sku);
        }
        return true;
    }

    @Override
    public void offerActivitySkuStockSubTask(ActivitySkuStockSubTaskVO subTaskVO) {
        // 间隔3秒在将扣减库存任务加入到队列中
        String queueKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_SKU_STOCK_DESC_QUEUE);
        RBlockingQueue<ActivitySkuStockSubTaskVO> blockingQueue = redisService.getBlockingQueue(queueKey);
        RDelayedQueue<ActivitySkuStockSubTaskVO> delayedQueue = redisService.getDelayedQueue(blockingQueue);
        delayedQueue.offer(subTaskVO, 3, TimeUnit.SECONDS);
    }

    @Override
    public ActivitySkuStockSubTaskVO pollAwardStockSubTask() {
        // 队列无元素返回空
        String queueKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_SKU_STOCK_DESC_QUEUE);
        RBlockingQueue<ActivitySkuStockSubTaskVO> blockingQueue = redisService.getBlockingQueue(queueKey);
        return blockingQueue.poll();
    }

    @Override
    public void decrActivitySkuCountSurplus(Long sku) {
        raffleActivitySkuDao.decrActivitySkuCountSurplus(sku);
    }

    @Override
    public void clearZeroActivitySkuCount(Long sku) {
        raffleActivitySkuDao.clearZeroActivitySkuCount(sku);
    }

    @Override
    public void createUserRaffleOrder(PartakeActivityOrderAggregate aggregate) {
        // 用户抽奖订单
        UserRaffleOrderEntity userRaffleOrderEntity = aggregate.getUserRaffleOrderEntity();
        UserRaffleOrder userRaffleOrder = new UserRaffleOrder();
        userRaffleOrder.setUserId(userRaffleOrderEntity.getUserId());
        userRaffleOrder.setActivityId(userRaffleOrderEntity.getActivityId());
        userRaffleOrder.setActivityName(userRaffleOrderEntity.getActivityName());
        userRaffleOrder.setStrategyId(userRaffleOrderEntity.getStrategyId());
        userRaffleOrder.setOrderId(userRaffleOrderEntity.getOrderId());
        userRaffleOrder.setOrderTime(userRaffleOrderEntity.getOrderTime());
        userRaffleOrder.setOrderState(userRaffleOrderEntity.getOrderState().getCode());

        transactionTemplate.execute(status -> {
            try {
                // 更新用户账户次数-总
                int decrTotalCount = raffleActivityAccountDao.decrCountSurplus(aggregate.getUserId(), aggregate.getActivityId());
                if (decrTotalCount != 1) {
                    throw new BizException("扣减用户总账户次数失败");
                }
                if (aggregate.isExistMonth()) {
                    // 更新用户账户次数-月
                    int decrMonthCount = raffleActivityAccountMonthDao.decrCountSurplus(aggregate.getUserId(), aggregate.getActivityId(), RaffleActivityAccountMonthEntity.currentMonth());
                    if (decrMonthCount != 1) {
                        throw new BizException("扣减用户月账户次数失败");
                    }
                } else {
                    // 新增用户账户次数-月
                    RaffleActivityAccountMonthEntity accountMonthEntity = aggregate.getRaffleActivityAccountMonth();
                    RaffleActivityAccountMonth raffleActivityAccountMonth = new RaffleActivityAccountMonth();
                    raffleActivityAccountMonth.setUserId(accountMonthEntity.getUserId());
                    raffleActivityAccountMonth.setActivityId(accountMonthEntity.getActivityId());
                    raffleActivityAccountMonth.setMonth(accountMonthEntity.getMonth());
                    raffleActivityAccountMonth.setMonthCount(accountMonthEntity.getMonthCount());
                    raffleActivityAccountMonth.setMonthCountSurplus(accountMonthEntity.getMonthCountSurplus() - 1);
                    raffleActivityAccountMonthDao.insert(raffleActivityAccountMonth);
                }
                // 更新总账户表月剩余次数
                int decrMonthCount = raffleActivityAccountDao.decrMonthCountSurplus(aggregate.getUserId(), aggregate.getActivityId());
                if (decrMonthCount != 1) {
                    throw new BizException("扣减用户总账户，月剩余次数失败");
                }
                if (aggregate.isExistDay()) {
                    // 更新用户账户次数-日
                    int decrDayCount = raffleActivityAccountDayDao.decrCountSurplus(aggregate.getUserId(), aggregate.getActivityId(), RaffleActivityAccountDayEntity.currentDay());
                    if (decrDayCount != 1) {
                        throw new BizException("扣减用户日账户次数失败");
                    }
                } else {
                    RaffleActivityAccountDayEntity accountDayEntity = aggregate.getRaffleActivityAccountDay();
                    // 日参与账户
                    RaffleActivityAccountDay raffleActivityAccountDay = new RaffleActivityAccountDay();
                    raffleActivityAccountDay.setUserId(accountDayEntity.getUserId());
                    raffleActivityAccountDay.setActivityId(accountDayEntity.getActivityId());
                    raffleActivityAccountDay.setDay(accountDayEntity.getDay());
                    raffleActivityAccountDay.setDayCount(accountDayEntity.getDayCount());
                    raffleActivityAccountDay.setDayCountSurplus(accountDayEntity.getDayCountSurplus() - 1);
                    raffleActivityAccountDayDao.insert(raffleActivityAccountDay);
                }
                // 更新总账户表日剩余次数
                int decrDayCount = raffleActivityAccountDao.decrDayCountSurplus(aggregate.getUserId(), aggregate.getActivityId());
                if (decrDayCount != 1) {
                    throw new BizException("扣减用户总账户，日剩余次数失败");
                }
                // 新增用户参与订单
                userRaffleOrderDao.insert(userRaffleOrder);
                return 1;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });

    }

    @Override
    public UserRaffleOrderEntity queryUserRaffleOrder(String userId, Long activityId, String orderState) {
        UserRaffleOrder userRaffleOrder = userRaffleOrderDao.queryUserRaffleOrder(userId, activityId, orderState);
        return BeanUtil.copyProperties(userRaffleOrder, UserRaffleOrderEntity.class);
    }

    @Override
    public RaffleActivityAccountEntity queryActivityAccount(String userId, Long activityId) {
        RaffleActivityAccount raffleActivityAccount = raffleActivityAccountDao.get(userId, activityId);
        if (Objects.isNull(raffleActivityAccount)) {
            return null;
        }
        RaffleActivityAccountEntity activityAccountEntity = new RaffleActivityAccountEntity();
        activityAccountEntity.setUserId(raffleActivityAccount.getUserId());
        activityAccountEntity.setActivityId(raffleActivityAccount.getActivityId());
        activityAccountEntity.setTotalCount(raffleActivityAccount.getTotalCount());
        activityAccountEntity.setTotalCountSurplus(raffleActivityAccount.getTotalCountSurplus());
        activityAccountEntity.setDayCount(raffleActivityAccount.getDayCount());
        activityAccountEntity.setDayCountSurplus(raffleActivityAccount.getDayCountSurplus());
        activityAccountEntity.setMonthCount(raffleActivityAccount.getMonthCount());
        activityAccountEntity.setMonthCountSurplus(raffleActivityAccount.getMonthCountSurplus());
        activityAccountEntity.setCreateTime(raffleActivityAccount.getCreateTime());
        activityAccountEntity.setUpdateTime(raffleActivityAccount.getUpdateTime());
        return activityAccountEntity;
    }

    @Override
    public RaffleActivityAccountMonthEntity queryActivityAccountMonth(String userId, Long activityId, String month) {
        RaffleActivityAccountMonth raffleActivityAccountMonth = raffleActivityAccountMonthDao.get(userId, activityId, month);
        if (Objects.isNull(raffleActivityAccountMonth)) {
            return null;
        }
        RaffleActivityAccountMonthEntity raffleActivityAccountMonthEntity = new RaffleActivityAccountMonthEntity();
        raffleActivityAccountMonthEntity.setUserId(raffleActivityAccountMonth.getUserId());
        raffleActivityAccountMonthEntity.setActivityId(raffleActivityAccountMonth.getActivityId());
        raffleActivityAccountMonthEntity.setMonth(raffleActivityAccountMonth.getMonth());
        raffleActivityAccountMonthEntity.setMonthCount(raffleActivityAccountMonth.getMonthCount());
        raffleActivityAccountMonthEntity.setMonthCountSurplus(raffleActivityAccountMonth.getMonthCountSurplus());
        raffleActivityAccountMonthEntity.setCreateTime(raffleActivityAccountMonth.getCreateTime());
        raffleActivityAccountMonthEntity.setUpdateTime(raffleActivityAccountMonth.getUpdateTime());
        return raffleActivityAccountMonthEntity;
    }

    @Override
    public RaffleActivityAccountDayEntity queryActivityAccountDay(String userId, Long activityId, String day) {
        RaffleActivityAccountDay raffleActivityAccountDay = raffleActivityAccountDayDao.get(userId, activityId, day);
        if (Objects.isNull(raffleActivityAccountDay)) {
            return null;
        }
        RaffleActivityAccountDayEntity raffleActivityAccountDayEntity = new RaffleActivityAccountDayEntity();
        raffleActivityAccountDayEntity.setUserId(raffleActivityAccountDay.getUserId());
        raffleActivityAccountDayEntity.setActivityId(raffleActivityAccountDay.getActivityId());
        raffleActivityAccountDayEntity.setDay(raffleActivityAccountDay.getDay());
        raffleActivityAccountDayEntity.setDayCount(raffleActivityAccountDay.getDayCount());
        raffleActivityAccountDayEntity.setDayCountSurplus(raffleActivityAccountDay.getDayCountSurplus());
        raffleActivityAccountDayEntity.setCreateTime(raffleActivityAccountDay.getCreateTime());
        raffleActivityAccountDayEntity.setUpdateTime(raffleActivityAccountDay.getUpdateTime());
        return raffleActivityAccountDayEntity;
    }

    @Override
    public List<ActivitySkuEntity> queryActivitySkuList(Long activityId) {
        List<RaffleActivitySku> raffleActivitySkuList = raffleActivitySkuDao.queryActivitySkuListByActivityId(activityId);
        if (CollectionUtils.isEmpty(raffleActivitySkuList)) {
            return Lists.newArrayList();
        }
        return raffleActivitySkuList.stream()
                .map(activitySku -> {
                    ActivitySkuEntity activitySkuEntity = new ActivitySkuEntity();
                    activitySkuEntity.setSku(activitySku.getSku());
                    activitySkuEntity.setActivityId(activitySku.getActivityId());
                    activitySkuEntity.setActivityCountId(activitySku.getActivityCountId());
                    activitySkuEntity.setStockCount(activitySku.getStockCount());
                    activitySkuEntity.setStockCountSurplus(activitySku.getStockCountSurplus());
                    return activitySkuEntity;
                }).collect(Collectors.toList());
    }

    @Override
    public Integer queryUserDayRaffleCount(String userId, Long strategyId) {
        RaffleActivity raffleActivity = raffleActivityDao.queryActivityByStrategyId(strategyId);
        if (Objects.isNull(raffleActivity)) {
            return 0;
        }
        // 获取用户当前日账户信息
        return this.queryUserDayRaffleCountByActivityId(userId, raffleActivity.getActivityId());
    }

    @Override
    public Integer queryUserDayRaffleCountByActivityId(String userId, Long activityId) {
        // 获取用户当前日账户信息
        RaffleActivityAccountDay raffleActivityAccountDay = raffleActivityAccountDayDao.get(userId, activityId, RaffleActivityAccountDay.currentDay());
        if (Objects.isNull(raffleActivityAccountDay)) {
            return 0;
        }
        return raffleActivityAccountDay.getDayCount() - raffleActivityAccountDay.getDayCountSurplus();
    }

    @Override
    public RaffleActivityAccountEntity queryUserActivityAccount(String userId, Long activityId) {
        RaffleActivityAccount activityAccount = raffleActivityAccountDao.get(userId, activityId);
        // 总账户不存在返回默认0账户
        if (Objects.isNull(activityAccount)) {
            return RaffleActivityAccountEntity.EMPTY_ACCOUNT;
        }
        RaffleActivityAccountEntity account = new RaffleActivityAccountEntity();
        account.setUserId(activityAccount.getUserId());
        account.setActivityId(activityAccount.getActivityId());
        account.setTotalCount(activityAccount.getTotalCount());
        account.setTotalCountSurplus(activityAccount.getTotalCountSurplus());
        // 月账户有值取月账户
        RaffleActivityAccountMonth accountMonth = raffleActivityAccountMonthDao.get(userId, activityId, RaffleActivityAccountMonth.currentMonth());
        if (Objects.nonNull(accountMonth)) {
            account.setMonthCount(accountMonth.getMonthCount());
            account.setMonthCountSurplus(accountMonth.getMonthCountSurplus());
        } else {
            account.setMonthCount(activityAccount.getMonthCount());
            account.setMonthCountSurplus(activityAccount.getMonthCountSurplus());
        }
        // 日账户有值取日账户
        RaffleActivityAccountDay accountDay = raffleActivityAccountDayDao.get(userId, activityId, RaffleActivityAccountDay.currentDay());
        if (Objects.nonNull(accountDay)) {
            account.setDayCount(accountDay.getDayCount());
            account.setDayCountSurplus(accountDay.getDayCountSurplus());
        } else {
            account.setDayCount(activityAccount.getDayCount());
            account.setDayCountSurplus(activityAccount.getDayCountSurplus());
        }
        return account;
    }

    @Override
    public ActivityOrderEntity queryActivityOrderByOutBusinessNo(String outBusinessNo) {
        RaffleActivityOrder raffleActivityOrder = raffleActivityOrderDao.queryActivityOrderByOutBusinessNo(outBusinessNo);
        return RaffleActivityOrder.convert2Entity(raffleActivityOrder);
    }

    @Override
    public void rechargeAccountByOrder(ActivityOrderEntity activityOrderEntity) {
        RaffleActivityOrder raffleActivityOrderReq = new RaffleActivityOrder();
        raffleActivityOrderReq.setUserId(activityOrderEntity.getUserId());
        raffleActivityOrderReq.setActivityId(activityOrderEntity.getActivityId());
        raffleActivityOrderReq.setOutBusinessNo(activityOrderEntity.getOutBusinessNo());
        raffleActivityOrderReq.setState(ActivityOrderStateEnum.COMPLETED.getCode());

        // 总账户
        RaffleActivityAccount raffleActivityAccountReq = new RaffleActivityAccount();
        raffleActivityAccountReq.setUserId(activityOrderEntity.getUserId());
        raffleActivityAccountReq.setActivityId(activityOrderEntity.getActivityId());
        raffleActivityAccountReq.setTotalCount(activityOrderEntity.getTotalCount());
        raffleActivityAccountReq.setTotalCountSurplus(activityOrderEntity.getTotalCount());
        raffleActivityAccountReq.setDayCount(activityOrderEntity.getDayCount());
        raffleActivityAccountReq.setDayCountSurplus(activityOrderEntity.getDayCount());
        raffleActivityAccountReq.setMonthCount(activityOrderEntity.getMonthCount());
        raffleActivityAccountReq.setMonthCountSurplus(activityOrderEntity.getMonthCount());
        // 月账户
        RaffleActivityAccountMonth raffleActivityAccountMonthReq = new RaffleActivityAccountMonth();
        raffleActivityAccountMonthReq.setUserId(activityOrderEntity.getUserId());
        raffleActivityAccountMonthReq.setActivityId(activityOrderEntity.getActivityId());
        raffleActivityAccountMonthReq.setMonth(RaffleActivityAccountMonth.currentMonth());
        raffleActivityAccountMonthReq.setMonthCount(activityOrderEntity.getMonthCount());
        raffleActivityAccountMonthReq.setMonthCountSurplus(activityOrderEntity.getMonthCount());
        // 日账户
        RaffleActivityAccountDay raffleActivityAccountDayReq = new RaffleActivityAccountDay();
        raffleActivityAccountDayReq.setUserId(activityOrderEntity.getUserId());
        raffleActivityAccountDayReq.setActivityId(activityOrderEntity.getActivityId());
        raffleActivityAccountDayReq.setDay(RaffleActivityAccountDay.currentDay());
        raffleActivityAccountDayReq.setDayCount(activityOrderEntity.getDayCount());
        raffleActivityAccountDayReq.setDayCountSurplus(activityOrderEntity.getDayCount());
        // 更新账户信息
        String lockKey = Constants.RedisKey.generate(Constants.RedisKey.ACTIVITY_ACCOUNT_LOCK, activityOrderEntity.getUserId(), activityOrderEntity.getActivityId());
        RLock lock = redisService.getLock(lockKey);
        try {
            lock.lock(3, TimeUnit.SECONDS);
            transactionTemplate.execute(status -> {
                // 新增/更新用户总账户
                RaffleActivityAccount raffleActivityAccount = raffleActivityAccountDao.get(activityOrderEntity.getUserId(), activityOrderEntity.getActivityId());
                if (Objects.isNull(raffleActivityAccount)) {
                    raffleActivityAccountDao.insert(raffleActivityAccountReq);
                } else {
                    raffleActivityAccountDao.update(raffleActivityAccountReq);
                }
                RaffleActivityAccount afterAccount = raffleActivityAccountDao.get(activityOrderEntity.getUserId(), activityOrderEntity.getActivityId());
                // 新增/更新用户月账户
                RaffleActivityAccountMonth raffleActivityAccountMonth = raffleActivityAccountMonthDao.get(activityOrderEntity.getUserId(), activityOrderEntity.getActivityId(), RaffleActivityAccountMonth.currentMonth());
                if (Objects.isNull(raffleActivityAccountMonth)) {
                    raffleActivityAccountMonthReq.setMonthCount(afterAccount.getMonthCount());
                    raffleActivityAccountMonthReq.setMonthCountSurplus(afterAccount.getMonthCountSurplus());
                    raffleActivityAccountMonthDao.insert(raffleActivityAccountMonthReq);
                } else {
                    raffleActivityAccountMonthDao.update(raffleActivityAccountMonthReq);
                }
                // 新增/更新用户日账户
                RaffleActivityAccountDay raffleActivityAccountDay = raffleActivityAccountDayDao.get(activityOrderEntity.getUserId(), activityOrderEntity.getActivityId(), RaffleActivityAccountDay.currentDay());
                if (Objects.isNull(raffleActivityAccountDay)) {
                    raffleActivityAccountDayReq.setDayCount(afterAccount.getDayCount());
                    raffleActivityAccountDayReq.setDayCountSurplus(afterAccount.getDayCountSurplus());
                    raffleActivityAccountDayDao.insert(raffleActivityAccountDayReq);
                } else {
                    raffleActivityAccountDayDao.update(raffleActivityAccountDayReq);
                }
                // 更新活动流水单状态
                raffleActivityOrderDao.updateComplelte(raffleActivityOrderReq);
                return 1;
            });
        } finally {
            lock.unlock();
        }
    }

    @Override
    public List<SkuProductEntity> querySkuProductList(Long activityId) {
        List<RaffleActivitySku> skuList = raffleActivitySkuDao.queryActivitySkuListByActivityId(activityId);
        if (CollectionUtils.isEmpty(skuList)) {
            return Lists.newArrayList();
        }
        List<Long> activityCountIds = skuList.stream().map(RaffleActivitySku::getActivityCountId).filter(Objects::nonNull).collect(Collectors.toList());
        List<RaffleActivityCount> activityCountList = raffleActivityCountDao.queryActivityCountList(activityCountIds);
        Map<Long, RaffleActivityCount> activityCountMap = activityCountList.stream().collect(Collectors.toMap(RaffleActivityCount::getActivityCountId, Function.identity()));
        return skuList.stream()
                .map(raffleActivitySku -> {
                    SkuProductEntity skuProductEntity = new SkuProductEntity();
                    skuProductEntity.setSku(raffleActivitySku.getSku());
                    skuProductEntity.setActivityId(raffleActivitySku.getActivityId());
                    skuProductEntity.setActivityCountId(raffleActivitySku.getActivityCountId());
                    skuProductEntity.setStockCount(raffleActivitySku.getStockCount());
                    skuProductEntity.setStockCountSurplus(raffleActivitySku.getStockCountSurplus());
                    skuProductEntity.setProductAmount(raffleActivitySku.getProductAmount());
                    // 活动次数配置
                    RaffleActivityCount raffleActivityCount = activityCountMap.get(raffleActivitySku.getActivityCountId());
                    SkuProductEntity.ActivityCount activityCount = new SkuProductEntity.ActivityCount();
                    activityCount.setTotalCount(raffleActivityCount.getTotalCount());
                    activityCount.setDayCount(raffleActivityCount.getDayCount());
                    activityCount.setMonthCount(raffleActivityCount.getMonthCount());
                    skuProductEntity.setActivityCount(activityCount);
                    return skuProductEntity;
                }).collect(Collectors.toList());
    }

    @Override
    public ActivityOrderEntity queryRecentOneMonthNoPayOrder(String userId, Long sku) {
        // 查询指定范围内的未支付活动流水单
        LocalDateTime startTime = LocalDateTime.now().minusMonths(1L);
        RaffleActivityOrder raffleActivityOrder = raffleActivityOrderDao.queryRecentOneMonthNoPayOrder(userId, sku, ActivityOrderStateEnum.WAIT_PAY.getCode(), startTime);
        return RaffleActivityOrder.convert2Entity(raffleActivityOrder);
    }
}
